package com.zuiacsn.java_gobang.game;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zuiacsn.java_gobang.JavaGobangApplication;
import com.zuiacsn.java_gobang.mapper.UserMapper;
import com.zuiacsn.java_gobang.model.User;
import lombok.Data;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

// 表示一个游戏房间
@Data
public class Room {
    private String roomId;
    private User user1;
    private User user2;
    private int whiteUser; // 表示先手

    public Room() {
        roomId = UUID.randomUUID().toString();
        onlineUserManager  = JavaGobangApplication.context.getBean(OnlineUserManager.class);
        roomManager = JavaGobangApplication.context.getBean(RoomManager.class);
        userMapper = JavaGobangApplication.context.getBean(UserMapper.class);

    }

    // 使用这个二维数组表示棋盘
    // 0 表示未落子
    // 1 表示user1的落子位置
    // 2 表示user2的落子位置
    private int[][] board = new int[15][15];
    ObjectMapper objectMapper = new ObjectMapper();

    OnlineUserManager onlineUserManager;
    RoomManager roomManager;
    UserMapper userMapper;


    // 服务器这边维护一个棋盘
    // 1.记录本次落子的位置
    // 2.判断胜负
    // 3.给客户端返回响应
    public void putChess(String payload) throws IOException {
        // 1.记录本次落子的位置
        GameRequest request = objectMapper.readValue(payload, GameRequest.class);
        int chess = request.getUserId() == user1.getUserId()?1:2;
        int userId = request.getUserId();
        int row = request.getRow();
        int col = request.getCol();
        if(board[row][col] != 0) {
            // 重复落子 ,理论上不会出现这种情况,因为客户端那边已经判断过了, 但是为了程序的稳健性 ,在进行一次判断
            System.out.println("当前位置"+row+" "+col+"已经有子了");
            return;
        }

        board[row][col] = chess;

        // 打印棋盘信息
        printBoard();

        // 2.判断胜负
        int winner = checkWinner(row,col,chess);
        // 3.给客户端返回响应 每个客户端都要发送
        GameResponse response = new GameResponse();
        response.setWinner(winner);
        response.setMessage("putChess");
        response.setUserId(userId);
        response.setRow(row);
        response.setCol(col);

        // 处理玩家下线情况
        WebSocketSession session1 = onlineUserManager.getFromRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromRoom(user2.getUserId());

        if(session1 == null){
            // 玩家一掉线了 玩家二获胜
            response.setWinner(user2.getUserId());
            System.out.println("玩家一掉线 !");
        }
        if(session2 == null){
            // 玩家二掉线了 玩家一获胜
            response.setWinner(user1.getUserId());
            System.out.println("玩家二掉线 !");
        }

        String respJson = objectMapper.writeValueAsString(response);
        if (session1 != null) {
            session1.sendMessage(new TextMessage(respJson));
        }

        if(session2 != null){
            session2.sendMessage(new TextMessage(respJson));
        }
        // 如果有一方获胜了, 将房间从房间管理器中进行移除
        if(winner != 0){
            System.out.println("胜负已分,房间即将销毁 ! roomId=" + roomId +"获胜方玩家Id为"+response.getWinner());
            // 更新数据
            userMapper.userWin(response.getWinner());
            userMapper.userLose(response.getWinner()==user1.getUserId()?user2.getUserId():user1.getUserId());
            // 销毁房间
            roomManager.remove(roomId,user1.getUserId(),user2.getUserId());
        }
    }

    private void printBoard() {
        System.out.println("======================================");
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                System.out.print(board[i][j]+" ");
            }
            System.out.println();
        }
        System.out.println("======================================");
    }

    /**
     * 判断胜负
     * @param row 行号
     * @param col 列号
     * @return 如果是 user1 胜返回 1 如果是user2胜返回2 胜负未分返回0
     */
    private int checkWinner(int row, int col,int chess) {
        // 1. 检查所有的行
        //    先遍历这五种情况
        for (int c = col - 4; c <= col; c++) {
            // 针对其中的一种情况, 来判定这五个子是不是连在一起了~
            // 不光是这五个子得连着, 而且还得和玩家落的子是一样~~ (才算是获胜)
            try {
                if (board[row][c] == chess
                        && board[row][c + 1] == chess
                        && board[row][c + 2] == chess
                        && board[row][c + 3] == chess
                        && board[row][c + 4] == chess) {
                    // 构成了五子连珠! 胜负已分!
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                // 如果出现数组下标越界的情况, 就在这里直接忽略这个异常.
                continue;
            }
        }

        // 2. 检查所有列
        for (int r = row - 4; r <= row; r++) {
            try {
                if (board[r][col] == chess
                        && board[r + 1][col] == chess
                        && board[r + 2][col] == chess
                        && board[r + 3][col] == chess
                        && board[r + 4][col] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 3. 检查左对角线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
            try {
                if (board[r][c] == chess
                        && board[r + 1][c + 1] == chess
                        && board[r + 2][c + 2] == chess
                        && board[r + 3][c + 3] == chess
                        && board[r + 4][c + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 4. 检查右对角线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
            try {
                if (board[r][c] == chess
                        && board[r + 1][c - 1] == chess
                        && board[r + 2][c - 2] == chess
                        && board[r + 3][c - 3] == chess
                        && board[r + 4][c - 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 胜负未分, 就直接返回 0 了.
        return 0;
    }

}
